#ifndef Bitmap_H_INCLUDED
#define Bitmap_H_INCLUDED

#include <stdint.h>
#include <stdbool.h>
#include "sdisk.h"

#define BITMASK_SIZE (SD_NUMSECTORS / 8 + (SD_NUMSECTORS % 8 > 0))

typedef struct {
	union Data {
		uint8_t value;
		struct Bits {
			uint8_t bit0 : 1;
			uint8_t bit1 : 1;
			uint8_t bit2 : 1;
			uint8_t bit3 : 1;
			uint8_t bit4 : 1;
			uint8_t bit5 : 1;
			uint8_t bit6 : 1;
			uint8_t bit7 : 1;
		} bits;
	} data[BITMASK_SIZE];
} Bitmask;

void bitmask_flip( Bitmask * bitmask, size_t location )
{
	size_t dataIndex = location / 8;
	size_t bitOffset = location % 8;

	switch ( bitOffset )
	{
		case 0:
			bitmask->data[dataIndex].bits.bit0 = ~bitmask->data[dataIndex].bits.bit0;
			break;
		case 1:
			bitmask->data[dataIndex].bits.bit1 = ~bitmask->data[dataIndex].bits.bit1;
			break;
		case 2:
			bitmask->data[dataIndex].bits.bit2 = ~bitmask->data[dataIndex].bits.bit2;
			break;
		case 3:
			bitmask->data[dataIndex].bits.bit3 = ~bitmask->data[dataIndex].bits.bit3;
			break;
		case 4:
			bitmask->data[dataIndex].bits.bit4 = ~bitmask->data[dataIndex].bits.bit4;
			break;
		case 5:
			bitmask->data[dataIndex].bits.bit5 = ~bitmask->data[dataIndex].bits.bit5;
			break;
		case 6:
			bitmask->data[dataIndex].bits.bit6 = ~bitmask->data[dataIndex].bits.bit6;
			break;
		case 7:
			bitmask->data[dataIndex].bits.bit7 = ~bitmask->data[dataIndex].bits.bit7;
			break;
	}
}

bool bitmask_isFree( const Bitmask * bitmask, size_t location )
{
	size_t dataIndex = location / 8;
	size_t bitOffset = location % 8;

	switch ( bitOffset )
	{
		case 0:
			return !bitmask->data[dataIndex].bits.bit0;
		case 1:
			return !bitmask->data[dataIndex].bits.bit1;
		case 2:
			return !bitmask->data[dataIndex].bits.bit2;
		case 3:
			return !bitmask->data[dataIndex].bits.bit3;
		case 4:
			return !bitmask->data[dataIndex].bits.bit4;
		case 5:
			return !bitmask->data[dataIndex].bits.bit5;
		case 6:
			return !bitmask->data[dataIndex].bits.bit6;
		case 7:
			return !bitmask->data[dataIndex].bits.bit7;
	}

	return false;
}

size_t bitmask_numFree( const Bitmask * bitmask )
{
    size_t i;
    size_t ret = 0;
    for ( i = 0; i < BITMASK_SIZE * 8; i++ )
    {
        if ( bitmask_isFree( bitmask, i ) )
            ret++;
    }

    return ret;
}

void bitmask_free( Bitmask * bitmask )
{
	size_t i;
	for ( i = 0; i < BITMASK_SIZE; i++ )
		bitmask->data[i].value = 0;

    //Mark sectors not on disk as not free
	size_t notValid = BITMASK_SIZE * 8 - SD_NUMSECTORS;

	for ( i = 1; i <= notValid; i++ )
		bitmask_flip( bitmask, BITMASK_SIZE * 8 - i );
}

int bitmask_getFree( Bitmask * bitmask, sector_t * out )
{
	size_t i;

	sector_t temp;
	temp.in_use = false;
	for ( i = 0; i < BITMASK_SIZE; i++ )
	{
		size_t j;
		for ( j = 0; j < 8; j++ )
		{
			temp.sector = (uint16_t)i * 8 + j;
			if ( bitmask_isFree( bitmask, temp.sector ) )
			{
				*out = temp;
				return 0;
			}
		}
	}

	return -1;
}

#endif // Bitmap_H_INCLUDED
